---
title: .family
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

Avant de lire ceci, pensez à vous renseigner sur [les providers](/docs/concepts2/providers)
et [comment les lires](/docs/concepts/reading).

Dans cette partie, nous allons parler en détail du modificateur de provider `.family`.

Le modifieur `.family` a un seul but : Créer un provider à partir de valeurs externes.

Certains cas d'utilisation communs pour `family` seraient :

- Combinaison de [FutureProvider] avec `.family` pour récupérer un `Message` à partir de son ID.
- Passer `Locale` à un provider, afin que nous puissions gérer les traductions (translations):

## Usage

Le fonctionnement des familles consiste à ajouter un paramètre supplémentaire au provider.
Ce paramètre peut ensuite être utilisé librement dans notre provider pour créer un état.

Par exemple, nous pourrions combiner `family` avec [FutureProvider] pour 
récupérer `Message` à partir de son ID :

```dart
final messagesFamily = FutureProvider.family<Message, String>((ref, id) async {
  return dio.get('http://my_api.dev/messages/$id');
});
```

Ensuite, lorsque on utilise notre provider `messagesFamily`, la syntaxe est légèrement modifiée. 
La syntaxe habituelle ne fonctionnera plus :

```dart
Widget build(BuildContext context, WidgetRef ref) {
  // Erreur – messagesFamily n'est pas un provider
  final response = ref.watch(messagesFamily);
}
```

A la place, nous devons passer un paramètre à `messagesFamily` :

```dart
Widget build(BuildContext context, WidgetRef ref) {
  final response = ref.watch(messagesFamily('id'));
}
```

:::info
Il est possible d'utiliser une famille avec différents paramètres simultanément.  Par exemple, on peut utiliser un `titleFamily` pour lire 
à la fois les traductions française et anglaise en même temps :

```dart
@override
Widget build(BuildContext context, WidgetRef ref) {
  final frenchTitle = ref.watch(titleFamily(const Locale('fr')));
  final englishTitle = ref.watch(titleFamily(const Locale('en')));

  return Text('fr: $frenchTitle en: $englishTitle');
}
```

:::

## Restrictions sur les paramètres


Pour que les familles fonctionnent correctement, il est essentiel que le paramètre 
passé à un provider ait un `hashCode` et un `==` cohérents.

Idéalement, le paramètre devrait être soit une primitive (bool/int/double/String), 
une constante (providers), ou un objet immuable qui surcharge (overrid) `==` et `hashCode`.

### _PRÉFÉRER_ Utilisation de `autoDispose` lorsque le paramètre n'est pas constant :


Vous pouvez vouloir utiliser les familles pour transmettre la saisie d'un champ de recherche à votre provider.
Mais cette valeur peut changer souvent et ne jamais être réutilisée.
Cela pourrait provoquer des fuites de mémoire car, par défaut, un provider n'est jamais détruit même s'il n'est plus utilisé.

Utiliser à la fois `.family` et `.autoDispose` corrige cette fuite de mémoire :

```dart
final characters = FutureProvider.autoDispose.family<List<Character>, String>((ref, filter) async {
  return fetchCharacters(filter: filter);
});
```

## Passage de plusieurs paramètres à une famille

Les familles n'ont pas de support intégré (built-in) pour transmettre plusieurs valeurs à un provider.

D'autre par contre, cette valeur peut être _n'importe quoi_ (pour autant 
qu'elle respecte les restrictions mentionnées précédemment).

Cela inclut :

- Le tuple de [tuple](http://pub.dev/packages/tuple).
- Les objets générés avec [Freezed] ou [built_value](https://pub.dev/packages/built_value).
- les objets utilisant [equatable](https://pub.dev/packages/equatable).

voici un example en utilisant [Freezed] et [equatable]:

<Tabs
  groupId="family"
  defaultValue="freezed"
  values={[
    { label: 'Freezed', value: 'freezed', },
    { label: 'Equatable', value: 'equatable', },
  ]}
>

<TabItem value="freezed">

```dart
@freezed
abstract class MyParameter with _$MyParameter {
  factory MyParameter({
    required int userId,
    required Locale locale,
  }) = _MyParameter;
}

final exampleProvider = Provider.autoDispose.family<Something, MyParameter>((ref, myParameter) {
  print(myParameter.userId);
  print(myParameter.locale);
  // Faire quelque chose avec userId/locale.
});

@override
Widget build(BuildContext context, WidgetRef ref) {
  int userId; // Lire le user ID de quelque part
  final locale = Localizations.localeOf(context);

  final something = ref.watch(
    exampleProvider(MyParameter(userId: userId, locale: locale)),
  );

  ...
}
```

</TabItem>
<TabItem value="equatable">

```dart
class MyParameter extends Equatable  {
  MyParameter({
    required this.userId,
    required this.locale,
  });

  final int userId;
  final Locale locale;

  @override
  List<Object> get props => [userId, locale];
}

final exampleProvider = Provider.family<Something, MyParameter>((ref, myParameter) {
  print(myParameter.userId);
  print(myParameter.locale);
  // Faire quelque chose avec userId/locale.
});

@override
Widget build(BuildContext context, WidgetRef ref) {
  int userId; // Lire le user ID de quelque part
  final locale = Localizations.localeOf(context);

  final something = ref.watch(
    exampleProvider(MyParameter(userId: userId, locale: locale)),
  );

  ...
}
```

</TabItem>
</Tabs>

[freezed]: https://pub.dev/packages/freezed
[provider]: https://pub.dev/documentation/riverpod/latest/riverpod/Provider-class.html
[equatable]: https://pub.dev/packages/equatable
[futureprovider]: https://pub.dev/documentation/riverpod/latest/riverpod/FutureProvider-class.html
